/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
 * MA  02110-1301, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package com.aionemu.gameserver.model.team.alliance;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javolution.util.FastList;

import com.aionemu.gameserver.model.Race;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.player.PlayerCommonData;
import com.aionemu.gameserver.model.gameobjects.player.RequestResponseHandler;
import com.aionemu.gameserver.model.team.Team;
import com.aionemu.gameserver.model.team.group.GroupEvent;
import com.aionemu.gameserver.model.team.group.LootGroupRules;
import com.aionemu.gameserver.model.team.group.PlayerGroup;
import com.aionemu.gameserver.model.team.interfaces.ITeamMember;
import com.aionemu.gameserver.model.team.league.League;
import com.aionemu.gameserver.network.aion.clientpackets.CM_PLAYER_STATUS_INFO.ePlayerStatus;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ALLIANCE_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_ALLIANCE_MEMBER_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUESTION_WINDOW;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.idfactory.IDFactory;

/**
 * @author lyahim
 *
 */
public class PlayerAlliance extends Team<PlayerGroup> implements ITeamMember
{
	private League league;
	private LootGroupRules	lootGroupRules	= new LootGroupRules();
	private List<Integer> vicCaptains = new ArrayList<Integer>();

	public PlayerAlliance(int teamId, PlayerGroup leader)
	{
		super(teamId, leader.getObjectId());
		addMember(leader);
	}

	@Override
	public void addMember(PlayerGroup member)
	{
		for (int i = 1000 ; i<1004 ;i++)
		{
			if (members.get(i) == null)
			{
				members.put(i, member);
				break;
			}
		}
		member.setPlayerAlliance(this);
		updateAllianceUIToEvent(member, GroupEvent.ENTER_GROUP);
	}

	@Override
	public boolean isFull()
	{
		return members.size() == 4;
	}

	@Override
	public String getName()
	{
		return "Player Alliance: " + getObjectId();
	}

	@Override
	public void getReward(Npc owner)
	{

	}

	public Collection<PlayerCommonData> getLeaders()
	{
		List<PlayerCommonData> list = new FastList<PlayerCommonData>();

		for (PlayerGroup memb : members.values())
			list.add(memb.getLeader());
		return list;
	}

	public boolean hasAuthority(Player player)
	{
		return getLeaders().contains(player);
	}

	public void updateAllianceUIToEvent(ITeamMember teamMamber, GroupEvent update)
	{
		switch(update)
		{
			case ENTER:
				if (teamMamber instanceof PlayerCommonData)
				{
					PlayerCommonData pcd = (PlayerCommonData)teamMamber;
					PacketSendUtility.sendPacket(pcd.getPlayer(), new SM_ALLIANCE_INFO(this));
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, new SM_ALLIANCE_MEMBER_INFO(pcd, getGroupObjectIdbyPlayerId(pcd.getObjectId()), update));
					for (PlayerGroup group : getMembers())
						for (PlayerCommonData pcd2 : group.getMembers())
							PacketSendUtility.sendPacket(pcd.getPlayer(), new SM_ALLIANCE_MEMBER_INFO(pcd2, group.getObjectId(), update));
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, SM_SYSTEM_MESSAGE.STR_FORCE_HE_ENTERED_FORCE(pcd.getName()));
					PacketSendUtility.sendPacket(pcd.getPlayer(), SM_SYSTEM_MESSAGE.STR_FORCE_ENTERED_FORCE());
				}
				break;
			case ENTER_GROUP:
				if (teamMamber instanceof PlayerGroup)
				{
					PacketSendUtility.broadcastPacketToTeam(null, this, new SM_ALLIANCE_INFO(this));
					for (PlayerCommonData pcd : ((PlayerGroup)teamMamber).getMembers())
					{
						updateAllianceUIToEvent(pcd, GroupEvent.ENTER);
					}
				}
				break;
			case DISCONNECTED:
				if (teamMamber instanceof PlayerCommonData)
				{
					PlayerCommonData pcd = (PlayerCommonData)teamMamber;
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, new SM_ALLIANCE_MEMBER_INFO(pcd, getGroupObjectIdbyPlayerId(pcd.getObjectId()), update));
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, SM_SYSTEM_MESSAGE.STR_FORCE_HE_BECOME_OFFLINE(pcd.getName()));
				}
				break;
			case LEAVE_TIMEOUT:
				if (teamMamber instanceof PlayerCommonData)
				{
					PlayerCommonData pcd = (PlayerCommonData)teamMamber;
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, new SM_ALLIANCE_MEMBER_INFO(pcd, getGroupObjectIdbyPlayerId(pcd.getObjectId()), update));
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, SM_SYSTEM_MESSAGE.STR_FORCE_HE_BECOME_OFFLINE_TIMEOUT(pcd.getName()));
				}
				break;
			default :
				if (teamMamber instanceof PlayerCommonData)
				{
					PlayerCommonData pcd = (PlayerCommonData)teamMamber;
					PacketSendUtility.broadcastPacketToTeam(pcd.getPlayer(), this, new SM_ALLIANCE_MEMBER_INFO(pcd, getGroupObjectIdbyPlayerId(pcd.getObjectId()), update));
				}
				
		}
	}

	public static void invitePlayerToAlliance(final Player inviter, final Player invited)
	{

		RequestResponseHandler responseHandler = new RequestResponseHandler(inviter)
		{
			@Override
			public void acceptRequest(VisibleObject requester, Player responder)
			{
				PlayerAlliance alliance = null;

				if (invited.isInAlliance())
				{
					if (inviter.isInAlliance() && invited.getPlayerAlliance() == inviter.getPlayerAlliance())
						PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_HE_IS_ALREADY_MEMBER_OF_OUR_ALLIANCE(invited.getName()));
					else
						PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_HE_IS_ALREADY_MEMBER_OF_OTHER_ALLIANCE(invited.getName()));
					return;
				}

				if (inviter.isInAlliance())
					alliance = inviter.getPlayerAlliance();
				else
				{
					PlayerGroup group = null;
					if (inviter.isInGroup())
					{
						group = inviter.getPlayerGroup();
					}
					else
					{
						group = new PlayerGroup(IDFactory.getInstance().nextId(), inviter, true);
					}
					alliance = new PlayerAlliance(IDFactory.getInstance().nextId(), group);
				}

				if (invited.isInGroup())
				{
					if (invited.getPlayerGroup().getLeader().getObjectId() != invited.getObjectId())
					{
						PacketSendUtility
								.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_CAN_NOT_INVITE_HIM_HE_IS_NOT_PARTY_LEADER(invited.getName()));
						return;
					}
					if (alliance.isFull())
					{
						PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_FORCE_INVITE_FAILED_NOT_ENOUGH_SLOT());
						return;
					}
					else
					{

						PlayerGroup targetGroup = invited.getPlayerGroup();
						alliance.addMember(targetGroup);
						return;
					}
				}
				else
				{
					for (PlayerGroup g : alliance.getMembers())
					{
						if (g.isFull())
							continue;
						g.addMember(invited.getObjectTemplate());
						return;
					}
					if (alliance.isFull())
					{
						PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_CANT_ADD_NEW_MEMBER());
						return;
					}
					PlayerGroup newGroup = new PlayerGroup(IDFactory.getInstance().nextId(), invited);
					alliance.addMember(newGroup);
				}
			}

			@Override
			public void denyRequest(VisibleObject requester, Player responder)
			{
				PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_HE_REJECT_INVITATION(responder.getName()));
			}
		};

		boolean result = invited.getResponseRequester().putRequest(SM_QUESTION_WINDOW.STR_REQUEST_ALLIANCE_INVITE, responseHandler);
		if (result)
		{
			if (invited.isInGroup())
			{
				PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_PARTY_ALLIANCE_INVITED_HIS_PARTY(invited.getName()));
			}
			else
			{
				PacketSendUtility.sendPacket(inviter, SM_SYSTEM_MESSAGE.STR_FORCE_INVITED_HIM(invited.getName()));
			}
			PacketSendUtility.sendPacket(invited, new SM_QUESTION_WINDOW(SM_QUESTION_WINDOW.STR_REQUEST_ALLIANCE_INVITE, inviter.getObjectId(), inviter.getName()));
		}
	}

	public void playerStatusInfo(Player myActivePlayer, ePlayerStatus status, int playerObjId)
	{
		//TODO must finish it
	}

	public static void handleGroupChange(PlayerAlliance alliance, int playerObjectId, int allianceGroupId, int secondObjectId)
	{
		//TODO must finish it
	}

	@Override
	public Collection<Player> getOnlineMembers()
	{
		List<Player> list = new FastList<Player>();

		for (PlayerGroup memb : getMembers())
			list.addAll(memb.getOnlineMembers());
		return list;
	}

	@Override
	public PlayerGroup getLeader()
	{
		return members.values().iterator().next();
	}

	@Override
	public void onMemberLogOut(int member)
	{
		super.onMemberLogOut(member);
	}

	@Override
	public Race getRace()
	{
		return getLeader().getRace();
	}

	@Override
	public void onMemberLogIn(int objectId)
	{
	}

	@Override
	public PlayerGroup getMemberById(int id)
	{
		return members.get(id);
	}
	
	private int getGroupObjectIdbyPlayerId(int playerObjectId)
	{
		int i = 1000;
		for (PlayerGroup group : getMembers())
		{
			if (group.getMemberById(playerObjectId) != null)
				return i;
			i++;
		}
		return 0;
	}

	/**
	 * @return Returns the league.
	 */
	public League getLeague()
	{
		return league;
	}

	/**
	 * @param league The league to set.
	 */
	public void setLeague(League league)
	{
		this.league = league;
	}

	/**
	 * @return Returns the lootGroupRules.
	 */
	public LootGroupRules getLootGroupRules()
	{
		return lootGroupRules;
	}

	/**
	 * @return Returns the vicCaptains.
	 */
	public List<Integer> getVicCaptains()
	{
		return vicCaptains;
	}

	/**
	 * @param vicCaptains The vicCaptains to set.
	 */
	public void setVicCaptains(List<Integer> vicCaptains)
	{
		this.vicCaptains = vicCaptains;
	}
}
